﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using StackExchange.Redis;
using BartonExtension;
using Cache.Model;
using Cache.Utils;

namespace Cache
{
    public class CacheManager
    {
        private string RediusDBConnectionString = ConfigurationExtensions.ValueOfConfig("cacheConnectionStr");
        private ConnectionMultiplexer conn { get; set; }
        private ConfigurationOptions connOptions { get; set; }

        static CacheManager cacheObj;

        public static CacheManager instance { 
            get
            {
                if (cacheObj == null)
                {
                    cacheObj = new CacheManager();
                }
                return cacheObj;
            }
            set
            {
                instance = value;
            }
        }
        public CacheManager()
        {
            connOptions = GetConnectionOptions();
            conn = ConnectionMultiplexer.Connect(connOptions);
        }

        public ConfigurationOptions GetConnectionOptions()
        {
            var _options = ConfigurationOptions.Parse(RediusDBConnectionString);
            _options.AbortOnConnectFail = true;
            _options.AllowAdmin = false;
            _options.ConnectRetry = 3;
            _options.ConnectTimeout = 3000;
            _options.KeepAlive = 180;
            return _options;
        }

        public async Task<CachingResult<CacheObject>> doCacheObjectAsync(CacheObject obj)
        {
            IDatabase db = GetCacheDB();
            CachingResult<CacheObject> result = await db.CacheSetAsync(obj);
            return result;
        }

        public async Task<CachingResult<T>> doCacheObjectAsync<T>(T obj,string key)
        {
            IDatabase db = GetCacheDB();
            CachingResult<T> result = await db.CacheSetAsync<T>(obj,key);
            return result;
        }

        public CachingResult<T> doCacheObject<T>(T obj,string key)
        {
            try
            {
                IDatabase db = GetCacheDB();
                CachingResult<T> result = db.CacheSet<T>(obj, key);
                return result;
            }
            catch(Exception e)
            {
                return new CachingResult<T>() { isSuccessCached = false };
            }
        }

        public CachingResult<CacheObject> doCacheObject(CacheObject obj)
        {
            return doCacheObject<CacheObject>(obj, obj.cacheIdentifier);
        }

        public async Task<T> objectFromCacheAsync<T>(string key)
        {
            IDatabase db = GetCacheDB();
            T obj = await db.CacheGetAsync<T>(key);
            return obj;
        }

        public async Task<CacheObject> objectFromCacheAsync(string key)
        {
            IDatabase db = GetCacheDB();
            CacheObject obj = await db.CacheGetAsync(key);
            return obj;
        }

        public T objectFromCache<T>(string key)
        {
            IDatabase db = GetCacheDB();
            T obj = db.CacheGet<T>(key);
            return obj;
        }
        public bool RemoveCache(string key)
        {
            IDatabase db = GetCacheDB();
            return db.RemoveCache(key);
        }
        public IDatabase GetCacheDB()
        {
            if (conn != null)
                return conn.GetDatabase();
            else
                return null;
        }
    }
}
